﻿using System.Data;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using NiuX.Data;

namespace NiuX;

public static class EFCoreExtensions
{
    /// <summary>
    /// set global 'IsDeleted=false' queryfilter for every entity
    /// </summary>
    /// <param name="modelBuilder"></param>
    public static void EnableSoftDeletionGlobalFilter(this ModelBuilder modelBuilder)
    {
        var entityTypesHasSoftDeletion = modelBuilder.Model.GetEntityTypes()
            .Where(e => e.ClrType.IsAssignableTo(typeof(ISoftDelete)));

        foreach (var entityType in entityTypesHasSoftDeletion)
        {
            var isDeletedProperty = entityType.FindProperty(nameof(ISoftDelete.IsDeleted));
            var parameter = Expression.Parameter(entityType.ClrType, "p");
            var filter = Expression.Lambda(Expression.Not(Expression.Property(parameter, isDeletedProperty.PropertyInfo)), parameter);
            entityType.SetQueryFilter(filter);
        }
    }

    public static IQueryable<T> Query<T>(this DbContext ctx) where T : class //, IEntity
    {
        return ctx.Set<T>().AsNoTracking();
    }

    /// <summary>
    /// Changes the database name. This require the databases in the same machine. NOTE: This only work for MySQL right now.
    /// </summary>
    /// <remarks>
    /// This only been used for supporting multiple databases in the same model. This require the databases in the same machine.
    /// </remarks>
    public static void ChangeDatabase(this DbContext dbContext, string nameOrConnectionString)
    {
        var connection = dbContext.Database.GetDbConnection();

        if (connection.State.HasFlag(ConnectionState.Open))
        {
            connection.ChangeDatabase(nameOrConnectionString);
        }
        else
        {
            connection.ConnectionString = nameOrConnectionString;
        }
    }
}